
static char RCSId[]="$Id: Inspector.m,v 1.1.1.1 1993/03/18 03:33:50 davis Exp $";


#import <appkit/Application.h>
#import <appkit/Button.h>
#import <appkit/Matrix.h>
#import <appkit/Panel.h>
#import <appkit/Pasteboard.h>
#import <appkit/publicWraps.h>	/* NXBeep()		*/

#import <dpsclient/wraps.h>

#import <objc/NXStringTable.h>

#import "GnuplotPlot.h"
#import "Inspector.h"
#import "Pane.h"
#import "Status.h"


@interface Inspector (Private)

- _swapPane:new;
- _determineNewStatusAndDoc;
- _updateForce:(BOOL)force all:(BOOL)all;

@end



@implementation Inspector


- init
{
    const char *validSend[] = {NXAsciiPboardType, NULL};
    const char *validReturn[] = {NXAsciiPboardType, NULL};
    NXRect frame;

    [super init];

    [NXApp loadNibSection: "Inspector.nib" 
		    owner: self
		withNames: NO
		 fromZone: [self zone]];

    status = nil;
    gnuplotPlot = nil;

    [window setFrameUsingName:"InspectorPanel"];
    [window setFrameAutosaveName:"InspectorPanel"];

    [noPane setTitle:[stringSet valueForStringKey:"inspectorNone"]];
    [generalPane setTitle:[stringSet valueForStringKey:"inspectorGeneral"]];
    [dataPane setTitle:[stringSet valueForStringKey:"inspectorData"]];
    [axesPane setTitle:[stringSet valueForStringKey:"inspectorAxes"]];
    [threeDPane setTitle:[stringSet valueForStringKey:"inspectorThreeD"]];

    [NXApp registerServicesMenuSendTypes: validSend
                          andReturnTypes: validReturn];

    [window getFrame:&frame];
    windowWidth = frame.size.width;

    noView = [noPane view];
    generalView = [generalPane view];
    dataView = [dataPane view];
    axesView = [axesPane view];
    threeDView = [threeDPane view];

    [[window contentView] allocateGState];

    [[window contentView] addSubview: noView];
    [[noView allocateGState] lockFocus];
    [noView unlockFocus];
    [noView moveTo:frame.size.width:30];

    [[window contentView] addSubview: generalView];
    [[generalView allocateGState] lockFocus];
    [generalView unlockFocus];
    [generalView moveTo:frame.size.width:30];

    [[window contentView] addSubview: dataView];
    [[dataView allocateGState] lockFocus];
    [dataView allocateGState];
    [dataView moveTo:frame.size.width:30];

    [[window contentView] addSubview: axesView];
    [[axesView allocateGState] lockFocus];
    [axesView unlockFocus];
    [axesView moveTo:frame.size.width:30];

    [[window contentView] addSubview: threeDView];
    [[threeDView allocateGState] lockFocus];
    [threeDView unlockFocus];
    [threeDView moveTo:frame.size.width:30];

    [noView moveTo:0:30];

    currentPane = noPane;
    currentView = noView;
    [window setMiniwindowIcon: [currentPane icon]];

    [window display];

    return self;
}



- window
{
    return window;
}



- showNoPane:sender
{
    if (status)
	[self _swapPane:noPane];
    return self;
}


- showGeneralPane:sender
{
    if (status)
	[self _swapPane:generalPane];
    return self;
}


- showDataPane:sender
{
    if (status)
	[self _swapPane:dataPane];
    return self;
}


- showAxesPane:sender
{
    if (status)
	[self _swapPane:axesPane];
    return self;
}


- showThreeDPane:sender
{
    if (status)
	[self _swapPane:threeDPane];
    return self;
}



/* 
 *  Services.  The Inspector instance is the inspector panel's 
 *  delegate, so these methods work when the inspector panel is the 
 *  key window.  We pass service requests on to the current 
 *  GnuplotPlot so that the filename of the current doc can always be 
 *  offered to servers, even when the inspector is the key window.
 */
- validRequestorForSendType:(NXAtom)sendType andReturnType:(NXAtom) returnType
{
    return [gnuplotPlot validRequestorForSendType:sendType 
				    andReturnType:returnType];
}


- (BOOL)writeSelectionToPasteboard:pboard types:(NXAtom *)types
{
    return [gnuplotPlot writeSelectionToPasteboard:pboard types:types];
}



/* 
 *  This method is similar to -windowDidUpdate except that it forces 
 *  ALL panes to update instead of just allowing the current pane to 
 *  possibly update.  This is necessary to keep a pane's OptionsPanels 
 *  up-to-date even when that pane is not selected.  (This is only a 
 *  problem after such operations as "Revert to Saved" when NXApp's 
 *  delegate must send this method.
 */
- update
{
    return [self _updateForce:YES all:YES];
}



/*  
 *  The user can force a plot by pressing the Plot button in the 
 *  Inspector. 
 */
- doPlot:sender
{
    if (gnuplotPlot)
	[gnuplotPlot plot:self];
    else
	NXBeep();

    return self;
}



/*  
 *  This method is similar to -update except that it updates only the 
 *  current pane, and allows it to decide whether or not it should 
 *  update itself instead of forcing it to update.
 */
- windowDidUpdate:sender
{
    return [self _updateForce:NO all:NO];
}


- selectPane:(int)aPane
{
    [buttonMatrix selectCellWithTag:aPane];

    if (status)
	switch (aPane) {
	case NO_INSPECTOR:		[self _swapPane:noPane];	break;
	case GENERAL_INSPECTOR:		[self _swapPane:generalPane];	break;
	case DATA_INSPECTOR:		[self _swapPane:dataPane];	break;
	case AXES_INSPECTOR:		[self _swapPane:axesPane];	break;
	case THREED_INSPECTOR:		[self _swapPane:threeDPane];	break;
	}
    else
	[self _swapPane:noPane];

    return self;
}


// Shuts up the compiler about unused RCSId
- (const char *) rcsid
{
    return RCSId;
}


@end


@implementation Inspector (Private)

- _swapPane:new
{
    /*  
     *  If "new" is nil, we look at the button matrix to determine 
     *  which inspector to swap in.
     */
    if (!new) {
        switch ([buttonMatrix selectedTag]) {
        case NO_INSPECTOR:
	    new = noPane;
            break;
        case GENERAL_INSPECTOR:
            new = generalPane;
            break;
        case DATA_INSPECTOR:
            new = dataPane;
            break;
        case AXES_INSPECTOR:
            new = axesPane;
            break;
        case THREED_INSPECTOR:
            new = threeDPane;
            break;
        }
    }


    /*  
     *  Now, if the new pane is not already visible, move it into the 
     *  inspector panel.
     */

    if (new != currentPane) {

	NXRect frame;
	View *newView = [new view];

	[[window contentView] getFrame:&frame];

	[currentPane didSwapOut:self];
	[[new didSwapIn:self] updateStatus:status doc:gnuplotPlot];
	[currentView moveTo:NX_WIDTH(&frame):30];
	[newView moveTo:0:30];
	[window display];

	[window setTitle:[new title]];
	[window setMiniwindowIcon:[new icon]];

	currentView = newView;
	currentPane = new;

    }

    return self;
}


- _determineNewStatusAndDoc
{
    Window *mainWindow = [NXApp mainWindow];

    /*  Set instance variables that indicate the current doc.  */

    if (mainWindow)  {

	gnuplotPlot = [mainWindow delegate];
	status = [gnuplotPlot status];

    } else {

	gnuplotPlot = nil;
	status = nil;

    }

    return self;
}


- _updateForce:(BOOL)force all:(BOOL)all
{
    BOOL needsRedisplay = NO;

    [self _determineNewStatusAndDoc];
    [window disableDisplay];

    if (!status) {			/* No current selection		*/

	[self _swapPane:noPane];
	needsRedisplay = YES;

    } else {				/* Update/replace controls	*/

	if (force) {

	    if (all) {

		needsRedisplay = [noPane forceUpdateStatus:status
						   doc:gnuplotPlot]? YES :NO;

		needsRedisplay = ([generalPane forceUpdateStatus:status
				  doc:gnuplotPlot]? YES :NO) || needsRedisplay;

		needsRedisplay = ([dataPane forceUpdateStatus:status
				  doc:gnuplotPlot]? YES :NO) || needsRedisplay;

		needsRedisplay = ([axesPane forceUpdateStatus:status
				  doc:gnuplotPlot]? YES :NO) || needsRedisplay;

		needsRedisplay = ([threeDPane forceUpdateStatus:status
				  doc:gnuplotPlot]? YES :NO) || needsRedisplay;

	    } else

		needsRedisplay = [currentPane forceUpdateStatus:status
			      doc:gnuplotPlot]? YES :NO;

	} else

	    needsRedisplay = [currentPane updateStatus:status doc:gnuplotPlot]?
								YES :NO;
	if (currentPane == noPane)
	    [self _swapPane:nil];	/* Get current pane from button */

    }

    [window reenableDisplay];
    if (needsRedisplay)
	[window display];

    /* 
     *  We disable the plot button if
     * 		1) No current status, or
     * 		2) Current plot's status reports that it can't plot
     */
    [plotButton setEnabled:status && [status canPlot]];
    
    return self;



}

@end
